using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Windows.Forms;
using Styx.WoWInternals.WoWObjects;
using Styx.WoWInternals;
using Styx.Common;
using Styx.CommonBot.Routines;
using Styx;
using Styx.CommonBot;

namespace FireMage
{
    public class FireMage : CombatRoutine
    {

        public override sealed string Name { get { return "LazyRaider FireMage by toNyx (manual targetting)"; } }
        public override WoWClass Class { get { return WoWClass.Mage; } }
        private static LocalPlayer Me { get { return StyxWoW.Me; } }

        public override bool WantButton { get { return true; } }
        public override void OnButtonPress() { var myGUI = new FireMageGUI(); myGUI.Show(); }

        public static void toNyxLog(string message, params object[] args) { Logging.Write("[toNyxDEBUG] " + message, args); }

        #region CONSTANT AND VARIABLES

        //START OF CONSTANTS ==============================

        // SPELLSTEALING, USING BUFFS FROM RAIDS!, NO DUNGEONS IDs HERE CARE ! /!\
        private readonly Dictionary<int, String> StealBuffs = new Dictionary<int, String>
                                                                  {
                                                                       {117309, "Cleansing Waters"}
                                                                  };

        //START OF SPELLS AND AURAS ==============================

        // AURAS & PROCS

        // -- FRIENDLY
        private const string ARCANE_BRILLANCE = "Arcane Brilliance";
        private const string MOLTEN_ARMOR = "Molten Armor";

        // -- OFFENSIVE
        private const string HEATING_UP = "Heating Up";
        private const string PYRO_PROC = "Pyroblast!";
        private const string IGNITE = "Ignite";

        // -- COOLDOWNS
        private const string P_O_M = "Presence of Mind";
        private const string MIRROR_IMAGE = "Mirror Image";
        private const string ALTER_TIME = "Alter Time";

        // UTILITY
        private const string COUNTERSPELL = "Counterspell";
        private const string POLYMORPH = "Polymorph";
        private const string SPELLSTEAL = "Spellsteal"; 
        private const string REMOVE_CURSE = "Remove Curse"; 
        private const string EVOCATION = "Evocation";
        private const string EVOCATION_BUFF = "Invoker's Energy"; 
        private const string RUNE_OF_POWER = "Rune of Power";  
        private const string ICE_BARRIER = "Ice Barrier";
        //private const string RING_OF_FROST = "Ring of Frost"; TODO !
        private const string CONJURE_REFRESHMENT = "Conjure Refreshment"; 
        private const string CONJURE_MANA_GEM = "Conjure Mana Gem";
        private const string MANA_GEM = "Mana Gem";
        private const string HEALTH_STONE = "Healthstone";

        // FIGHTINGUUUUUU
        private const string FIREBALL = "Fireball";
        private const string COMBUSTION = "Combustion";
        private const string PYROBLAST = "Pyroblast";
        private const string INFERNO_BLAST = "Inferno Blast";
        private const string LIVING_BOMB= "Living Bomb";
        private const string SCORCH = "Scorch";
        private const string FLAMESTRIKE = "Flamestrike";

        // SLACKINGUUUUU
        private const string ICE_BLOCK = "Ice Block";


        //END OF SPELLS AND AURAS ==============================

        //END OF CONSTANTS ==============================

        //START OF CUSTOM VARS
        public string LastSpell = "";
        public WoWUnit NearestTank = null;
        public WoWUnit GetTankTarget = null;
        public static bool HaveFood { get { return StyxWoW.Me.BagItems.Any(item => item.Entry == 80610); } }
        private static bool HaveManaGem { get { return StyxWoW.Me.BagItems.Any(i => i.Entry == 36799 || i.Entry == 81901); } }
        private static bool HaveHealthStone { get { return StyxWoW.Me.BagItems.Any(i => i.Entry == 5512); } }

        #endregion

        public override void Initialize()
        {
            toNyxLog("Combat Routine Loaded... It's raping time!");
            Hotkeys_Init();
        }

        #region Resting

        public override bool NeedRest
        {
            get { return Me.HealthPercent <= 65 && Me.IsAlive; }
        }

        public override void Rest()
        {
            if (NeedRest)
                Styx.CommonBot.Rest.Feed();
        }

        #endregion

        #region Pull Buffs

        public override bool NeedPullBuffs { get { return false; } }

        public override void PullBuff() { }

        #endregion

        #region Pre Combat Buffs

        public override bool NeedPreCombatBuffs { get { return true; } }

        public override void PreCombatBuff()
        {
            ConjureFood();
            MakeManaGem();
            MoltenArmor();
            ArcaneBrilliance();
        }

        #endregion

        #region Combat Buffs

        public override bool NeedCombatBuffs { get { return false; } }

        public override void CombatBuff() { }

        #endregion

        #region Heal

        public override bool NeedHeal { get { return false; } }

        public override void Heal() { }

        #endregion

        #region Falling

        public void HandleFalling() { }

        #endregion

        #region Combat

        public override void Combat()
        {
            Facing();

            // Check for forgotten PreCombatBuff
            MoltenArmor();
            ArcaneBrilliance();

            // Mana Gem
            UseManaGem();

            // Defensive checks
            IceBlock();
            IceBarrier();
            UseHealthStone();

            LivingBomb(); // REFRESH?

            // Talents Checks
            Evocation();
            RuneOfPower();

            if (Me.IsMoving)
                Scorch();

            // Priority & Utility spells
            Polymorph();
            CounterSpell();
            SpellSteal();
            Decursing();

            // Cooldowns
            MirrorImage();
            AlterTime();
            PresenceOfMind();

            // Check for AOE Routine
            if (FireMageSettings.Instance.EnableAOE)
            {
                if (Adds())
                    LivingBombAOE();
                if (Adds())
                    FlameStrike();
            }

            // Time to deal damages!
            Combustion();
            InfernoBlast();
            Pyroblast();
               
            Fireball();
        }

        #endregion

        #region Spells

        // BUFFS

        public bool ArcaneBrilliance()
        {
            if (SpellManager.CanCast(ARCANE_BRILLANCE) && !Me.HasAura(ARCANE_BRILLANCE) && LastSpell != ARCANE_BRILLANCE && !Me.Mounted)
            {
                SpellManager.Cast(ARCANE_BRILLANCE);
                toNyxLog(ARCANE_BRILLANCE);
                LastSpell = ARCANE_BRILLANCE;
                StyxWoW.SleepForLagDuration();
                return true;
            }
            return false;
        } //Check

        public bool MoltenArmor() 
        {
            if (SpellManager.CanCast(MOLTEN_ARMOR) && !Me.HasAura(MOLTEN_ARMOR) && LastSpell != MOLTEN_ARMOR && !Me.IsCasting && !Me.Mounted)
            {
                SpellManager.Cast(MOLTEN_ARMOR);
                toNyxLog(MOLTEN_ARMOR);
                LastSpell = MOLTEN_ARMOR;
                StyxWoW.SleepForLagDuration();
                return true;
            }
            return false;
        }  //Check

        // TALENT BASED

        public bool Evocation()
        {
            // SETTINGS CHECK
            if (!FireMageSettings.Instance.UseEvocation) return false;

            bool BasicEvocationConditions = Me.Combat && SpellManager.CanCast(EVOCATION) && !Me.IsMoving;
            bool AdditionnalEvocationConditions = false;

            if (FireMageSettings.Instance.KeepEvocationBuff)
                AdditionnalEvocationConditions = !Me.HasAura(EVOCATION_BUFF);

            if (FireMageSettings.Instance.EvocBelowThreshold)
                AdditionnalEvocationConditions = Me.ManaPercent < FireMageSettings.Instance.EvocThresholdMP;

            if (BasicEvocationConditions && AdditionnalEvocationConditions)
            {
                toNyxLog(EVOCATION);
                SpellManager.Cast(EVOCATION);
                LastSpell = EVOCATION;
                return true;
            }
            return false;
        }

        public bool RuneOfPower()
        {
            // SETTINGS CHECK
            if (!FireMageSettings.Instance.UseRoP) return false;

            if (!Me.IsMoving && LastSpell != RUNE_OF_POWER && !Me.HasAura(RUNE_OF_POWER) && Me.Combat && SpellManager.CanCast(RUNE_OF_POWER))
            {
                toNyxLog(RUNE_OF_POWER);
                SpellManager.Cast(RUNE_OF_POWER);
                LastSpell = RUNE_OF_POWER;
                return SpellManager.ClickRemoteLocation(Me.Location);
            }

            return false;

        }

        // OFFENSIVE

        public bool Fireball()
        {
            if (Me.CurrentTarget == null) return false;
            if (Me.Combat && SpellManager.CanCast(FIREBALL) && !Me.IsCasting && !Me.Mounted)
            {
                toNyxLog(FIREBALL);
                SpellManager.Cast(FIREBALL);
                LastSpell = FIREBALL;
                return true;
            }
            return false;
        }

        public bool Combustion()
        {
            if (Me.CurrentTarget == null) return false;
            if (SpellManager.CanCast(COMBUSTION) && Me.CurrentTarget.HasAura(IGNITE))
            {
                toNyxLog(COMBUSTION);
                SpellManager.Cast(COMBUSTION);
                LastSpell = COMBUSTION;
                return true;
            }
            return false;
        }

        public bool Pyroblast()
        {
            if (Me.CurrentTarget == null) return false;

            if(SpellManager.CanCast(PYROBLAST) && (Me.HasAura(PYRO_PROC) || Me.HasAura(P_O_M)))
            {
                toNyxLog(PYROBLAST);
                SpellManager.Cast(PYROBLAST);
                LastSpell = PYROBLAST;
                return true;
            }
            return false;
        }

        public bool LivingBomb()
        {
            if (Me.CurrentTarget == null) return false;
            if (SpellManager.CanCast(LIVING_BOMB) && /*UnfriendlyUnits.Count() < 3 &&*/ (!Me.CurrentTarget.HasAura(LIVING_BOMB) || (MyLivingBomb_Timeleft(LIVING_BOMB, Me.CurrentTarget) <= 2000)))
            {
                toNyxLog(LIVING_BOMB + " on " + Me.CurrentTarget.Name + " (Timeleft : " + MyLivingBomb_Timeleft(LIVING_BOMB, Me.CurrentTarget) + " ms)");
                SpellManager.Cast(LIVING_BOMB, Me.CurrentTarget);
                LastSpell = LIVING_BOMB;
                return true;
            }
            return false;
        }

        public bool LivingBombAOE()
        {
            if (Me.CurrentTarget == null) return false;

            if (GetEveryDottableTargets(40f).Count() < 3) return false;

            if (AllEnemyMobsHasMyDOT(LIVING_BOMB).Count() >= 3) return false;

            WoWUnit TargetForMultidot = NextApplyDOTTarget(LIVING_BOMB, 40, 2000);
            if (TargetForMultidot != null)
            {
                toNyxLog("[AOE] " + LIVING_BOMB + " on " + TargetForMultidot.Name);
                SpellManager.Cast(LIVING_BOMB, TargetForMultidot);
                LastSpell = LIVING_BOMB;
                return true;
            }
                
            return false;
        }

        public bool InfernoBlast()
        {
            if (Me.CurrentTarget == null) return false;
            if (SpellManager.CanCast(INFERNO_BLAST) && Me.HasAura(HEATING_UP))
            {
                toNyxLog(INFERNO_BLAST);
                SpellManager.Cast(INFERNO_BLAST);
                LastSpell = INFERNO_BLAST;
                return true;
            }
            return false;
        }

        public bool Scorch()
        {
            if (Me.CurrentTarget == null) return false;
            if (SpellManager.CanCast(SCORCH) && Me.IsMoving)
            {
                toNyxLog("We are moving, casting " + SCORCH);
                SpellManager.Cast(SCORCH);
                LastSpell = SCORCH;
                return true;
            }
            return false;
        }

        // OFFENSIVE AoE

        public bool FlameStrike()
        {
            if (Me.CurrentTarget == null) return false;
            if (FireMageSettings.Instance.UseFlameStrike && SpellManager.CanCast(FLAMESTRIKE) && !Me.Mounted && GetSpellCooldown(FLAMESTRIKE).TotalSeconds < 1 && !Me.IsChanneling)
            {
                SpellManager.Cast(FLAMESTRIKE);
                SpellManager.ClickRemoteLocation(Me.CurrentTarget.Location);
                toNyxLog(FLAMESTRIKE);
                LastSpell = FLAMESTRIKE;
                return true;
            }
            return false;
        }

        // COOLDOWNS

        public bool PresenceOfMind()
        {
            if (!IsTargetBoss()) return false;
            if (SpellManager.CanCast(P_O_M) && GetSpellCooldown(P_O_M).TotalSeconds < 1 && IsTargetBoss() && !Me.Mounted)
            {
                SpellManager.Cast(P_O_M);
                toNyxLog(P_O_M);
                LastSpell = P_O_M;
                return true;
            }
            return false;
        }

        public bool MirrorImage()
        {
            if (!IsTargetBoss()) return false;
            if (SpellManager.CanCast(MIRROR_IMAGE) && GetSpellCooldown(MIRROR_IMAGE).TotalSeconds < 1 && IsTargetBoss() && !Me.Mounted)
            {
                SpellManager.Cast(MIRROR_IMAGE);
                toNyxLog(MIRROR_IMAGE);
                LastSpell = MIRROR_IMAGE;
                return true;
            }
            return false;
        }

        public bool AlterTime()
        {
            if (!IsTargetBoss()) return false;
            if (SpellManager.CanCast(ALTER_TIME) && Me.HasAura(EVOCATION_BUFF) && Me.HasAura(PYRO_PROC))
            {
                toNyxLog(ALTER_TIME);
                return SpellManager.Cast(ALTER_TIME);
            }

            return false;
        }

        // DEFENSIVE

        public bool IceBlock()
        {
            if (FireMageSettings.Instance.UseIceBlock)
            {
                if (Me.Combat && SpellManager.CanCast(ICE_BLOCK) && Me.HealthPercent < FireMageSettings.Instance.IceBlockHP && !StyxWoW.Me.ActiveAuras.ContainsKey("Hypothermia"))
                {
                    toNyxLog(ICE_BLOCK);
                    SpellManager.Cast(ICE_BLOCK);
                    LastSpell = ICE_BLOCK;
                    return true;
                }
            }
            return false;
        }

        public bool UseHealthStone()
        {
            if (!FireMageSettings.Instance.UseHealthStone) return false;

            if (Me.Combat && HaveHealthStone)
            {
                WoWItem myStone = StyxWoW.Me.BagItems.First(i => i.Entry == 5512);
                if (myStone.CooldownTimeLeft.TotalSeconds < 1 && Me.HealthPercent < FireMageSettings.Instance.HealthStoneHP && !Me.Mounted)
                {
                    myStone.Use();
                    toNyxLog(HEALTH_STONE);
                    LastSpell = HEALTH_STONE;
                    return true;
                }
            }

            return false;
        }

        public bool IceBarrier()
        {
            if (!FireMageSettings.Instance.UseIceBarrier) return false;

            if (Me.Combat && !Me.HasAura(ICE_BARRIER) && SpellManager.CanCast(ICE_BARRIER) && GetSpellCooldown(ICE_BARRIER).TotalSeconds < 1 && !Me.Mounted)
            {
                SpellManager.Cast(ICE_BARRIER);
                toNyxLog(ICE_BARRIER);
                LastSpell = ICE_BARRIER;
                return true;

            }

            return false;
        }

        // UTILITY

        public bool Polymorph()
        {
            // SETTINGS CHECK
            if (!FireMageSettings.Instance.UsePolymorphOnFocus) return false;

            WoWUnit focus = Me.FocusedUnit;

            // SETTINGS CHECK
            if (focus != null)
            {
                if (FireMageSettings.Instance.DisablePolymorphOnBosses && IsFocusBoss()) return false;

                if (!focus.HasAura(POLYMORPH) || focus.GetAuraByName(POLYMORPH).Duration <= 10)
                {
                    if ((focus.IsBeast || focus.IsHumanoid)
                        && focus.Attackable
                        && focus.InLineOfSpellSight
                        && (focus.Distance - focus.CombatReach - 1) <= 3
                        && SpellManager.CanCast(POLYMORPH, focus))
                    {
                        toNyxLog(POLYMORPH + "on " + focus.Name);
                        SpellManager.Cast(POLYMORPH, focus);
                    }
                }
            }


            return false;
        }

        public bool CounterSpell()
        {
            if (Me.CurrentTarget == null) return false;

            WoWUnit myTarget = Me.CurrentTarget;

            if (GetSpellCooldown(COUNTERSPELL).TotalSeconds < 1
                && SpellManager.CanCast(COUNTERSPELL)
                && myTarget != null)
            {
                if ((myTarget.IsCasting || myTarget.IsCastingHealingSpell)
                && myTarget.CanInterruptCurrentSpellCast
                && !Me.Mounted)
                {
                    toNyxLog(COUNTERSPELL + " on " + myTarget.Name);
                    SpellManager.Cast(COUNTERSPELL, myTarget);
                    LastSpell = COUNTERSPELL;
                    return true;
                }
            }
            return false;
        }

        public bool SpellSteal()
        {
            if (Me.CurrentTarget == null) return false;

            if (IsTargetBoss())
            {
                WoWUnit myTarget;

                if (Me.FocusedUnit != null && Me.FocusedUnit.Attackable && Me.FocusedUnit.Distance - Me.FocusedUnit.CombatReach - 1 <= 30 && Me.FocusedUnit.InLineOfSpellSight)
                    myTarget = Me.FocusedUnit;
                else
                    myTarget = Me.CurrentTarget;

                if (myTarget != null && SpellManager.CanCast(SPELLSTEAL) && StyxWoW.Me.ManaPercent > 40)
                {
                    using (StyxWoW.Memory.AcquireFrame())
                    {
                        foreach (KeyValuePair<int, string> spell in StealBuffs.Where(spell => myTarget.ActiveAuras.ContainsKey(spell.Key.ToString(CultureInfo.InvariantCulture))))
                        {
                            toNyxLog(SPELLSTEAL + "( " + spell.Value + " ) on " + myTarget.Name);
                            SpellManager.Cast(SPELLSTEAL, myTarget);
                            LastSpell = SPELLSTEAL;
                            return true;
                        }

                    }
                }

                return false;
            }
            return false;
        }

        public bool Decursing()
        {
            if (FireMageSettings.Instance.UseDecurse && SpellManager.CanCast(REMOVE_CURSE))
            {
                WoWPlayer player = GetDecurseTarget(40f);

                if (player != null && player.Distance - player.CombatReach - 1 <= 40f && player.InLineOfSight)
                {
                    toNyxLog(REMOVE_CURSE + " on " + player.Name + " [ " + player.Class + " ]");
                    return SpellManager.Cast(REMOVE_CURSE, player);
                }
            }
            return false;
        }

        public bool ConjureFood()
        {
            // SETTINGS CHECK
            if (!FireMageSettings.Instance.ConjureFood) return false;

            if (!Me.Mounted && !Me.IsCasting)
            {
                if (!HaveFood)
                {
                    if (SpellManager.CanCast(CONJURE_REFRESHMENT) && LastSpell != CONJURE_REFRESHMENT)
                    {
                        SpellManager.Cast(CONJURE_REFRESHMENT);
                        toNyxLog(CONJURE_REFRESHMENT);

                        LastSpell = CONJURE_REFRESHMENT;
                        return true;
                    }
                }
            }
            return false;
        }

        public bool MakeManaGem()
        {
            // SETTINGS CHECK
            if (!FireMageSettings.Instance.UseManaGem) return false;

            if (!Me.Mounted && !Me.IsCasting)
            {
                if (!HaveManaGem)
                {
                    if (SpellManager.CanCast(CONJURE_MANA_GEM) && LastSpell != CONJURE_MANA_GEM)
                    {
                        SpellManager.Cast(CONJURE_MANA_GEM);
                        toNyxLog(CONJURE_MANA_GEM);
                        LastSpell = CONJURE_MANA_GEM;
                        return true;
                    }
                }
            }
            return false;
        }

        public bool UseManaGem()
        {
            // SETTINGS CHECK
            if (!FireMageSettings.Instance.UseManaGem) return false;

            if (Me.Combat && HaveManaGem)
            {
                WoWItem myGem = StyxWoW.Me.BagItems.First(i => i.Entry == 36799 || i.Entry == 81901);
                if (myGem.CooldownTimeLeft.TotalSeconds < 1 && Me.ManaPercent <= FireMageSettings.Instance.ManaGemMP && !Me.Mounted)
                {
                    myGem.Use();
                    toNyxLog(MANA_GEM);
                    LastSpell = MANA_GEM;
                    return true;
                }
            }

            return false;
        }

        #endregion

        #region SpellsCooldownsManagement

        public static TimeSpan GetSpellCooldown(string spell)
        {
            SpellFindResults results;
            if (SpellManager.FindSpell(spell, out results))
            {
                if (results.Override != null)
                    return results.Override.CooldownTimeLeft;
                return results.Original.CooldownTimeLeft;
            }
            return TimeSpan.MaxValue;
        }

        #endregion

        #region MyAuraTimeLeft

        public double MyAuraTimeLeft(string auraName, WoWUnit u)
        {
            using (StyxWoW.Memory.AcquireFrame())
            {
                if (u == null || !u.IsValid || !u.IsAlive)
                    return 0;

                WoWAura aura = u.GetAllAuras().FirstOrDefault(a => a.Name == auraName && a.CreatorGuid == Me.Guid);

                if (aura == null)
                    return 0;

                return aura.TimeLeft.TotalMilliseconds;
            }
        }

        public double MyAuraTimeLeft(int auraID, WoWUnit u)
        {
            using (StyxWoW.Memory.AcquireFrame())
            {
                if (u == null || !u.IsValid || !u.IsAlive)
                    return 0;

                WoWAura aura = u.GetAllAuras().FirstOrDefault(a => a.SpellId == auraID && a.CreatorGuid == Me.Guid);

                if (aura == null)
                    return 0;

                return aura.TimeLeft.TotalMilliseconds;
            }
        }

        #endregion

        #region FacingManagement

        public void Facing()
        {
            if (Me.CurrentTarget == null || Me.CurrentTarget.IsDead) return;
            if (Me.CurrentTarget.InLineOfSpellSight && !Me.IsMoving)
            {
                Me.CurrentTarget.Face();
            }
        }

        #endregion

        #region TargetChecks

        private bool IsTargetBoss()
        {
            if (Me.CurrentTarget == null) return false;
            if (Me.CurrentTarget.CreatureRank == WoWUnitClassificationType.WorldBoss)
                return true;
            if (Me.CurrentTarget.CreatureRank == WoWUnitClassificationType.Elite && Me.CurrentTarget.MaxHealth >= 5000000)
                return true;
            if (Me.CurrentTarget.CreatureRank == WoWUnitClassificationType.Elite && Me.CurrentTarget.Level >= Me.Level && (!Me.GroupInfo.IsInParty || !Me.IsInInstance))
                return true;
            if (Me.CurrentTarget.Name.Contains("Training Dummy"))
                return true;

            return false;
        }

        private bool IsFocusBoss()
        {
            if (Me.FocusedUnit == null) return false;
            if (Me.FocusedUnit.CreatureRank == WoWUnitClassificationType.WorldBoss)
                return true;
            if (Me.FocusedUnit.CreatureRank == WoWUnitClassificationType.Elite && Me.FocusedUnit.MaxHealth >= 5000000)
                return true;
            if (Me.FocusedUnit.CreatureRank == WoWUnitClassificationType.Elite && Me.FocusedUnit.Level >= Me.Level && (!Me.GroupInfo.IsInParty || !Me.IsInInstance))
                return true;
            if (Me.FocusedUnit.Name.Contains("Training Dummy"))
                return true;

            return false;
        }

        public static bool IsEnemy(WoWUnit u)
        {
            if (u == null || !u.CanSelect || !u.Attackable || !u.IsAlive || u.IsNonCombatPet || u.IsCritter)
                return false;

            if (!u.IsPlayer)
                return u.IsHostile || u.Aggro || u.PetAggro || (!Me.IsInInstance && u.Name.Contains("Dummy"));

            WoWPlayer p = u.ToPlayer();
            if (p != null)
                return p.IsHorde != StyxWoW.Me.IsHorde;

            return false;
        }

        public WoWPlayer GetDecurseTarget(double range)
        {
            return (from unit in ObjectManager.GetObjectsOfTypeFast<WoWPlayer>()
                    orderby unit.HealthPercent ascending
                    where (!unit.IsDead
                    && !unit.IsGhost
                    && unit.Distance - unit.CombatReach - 1 <= range
                    && unit.InLineOfSpellSight
                    && unit.ActiveAuras.Any(a => a.Value.IsHarmful && a.Value.Spell.DispelType == WoWDispelType.Curse)
                    && (unit.IsInMyPartyOrRaid || unit.Guid == Me.Guid))
                    select unit).FirstOrDefault();
        }

        #endregion

        #region AddCounting

        public static bool Adds()
        {
            List<WoWUnit> mobList = ObjectManager.GetObjectsOfType<WoWUnit>(false).FindAll(unit =>
                    Me.GotTarget
                    && unit.IsAlive
                    && unit.Guid != Me.Guid
                    && !unit.IsFriendly
                    && unit.IsHostile
                    && unit.Attackable
                    && !unit.IsTotem
                    && !unit.IsCritter
                    && !unit.IsNonCombatPet
                    && (unit.Location.Distance(Me.CurrentTarget.Location) <= 10 || unit.Location.Distance2D(Me.CurrentTarget.Location) <= 10));

            return mobList.Count >= FireMageSettings.Instance.MinimumEnemiesAOE;

        }

        #endregion addCounting

        #region Multi-dot Handling for Living Bomb (enums etc..)

        // Returns every enemy mob
        public IEnumerable<WoWUnit> AllEnemyMobs { get { return ObjectManager.ObjectList.Where(o => o is WoWUnit && IsEnemy(o.ToUnit())).Select(o => o.ToUnit()).ToList(); } }
        // Returns every unfriendly unit
        public IEnumerable<WoWUnit> UnfriendlyUnits { get { return ObjectManager.GetObjectsOfType<WoWUnit>(true, false).Where(u => !u.IsDead && u.CanSelect && u.Attackable && !u.IsFriendly); } }
        // Returns nearby unfriendly units
        public IEnumerable<WoWUnit> NearbyUnfriendlyUnits
        {
            get
            {
                Type typeWoWUnit = typeof(WoWUnit);
                Type typeWoWPlayer = typeof(WoWPlayer);
                List<WoWObject> objectList = ObjectManager.ObjectList;

                return (from t1 in objectList let type = t1.GetType() where type == typeWoWUnit || type == typeWoWPlayer select t1).OfType<WoWUnit>().ToList();
            }
        }
        // Returns every dottable target
        public IEnumerable<WoWUnit> GetEveryDottableTargets(double range) { return AllEnemyMobs.Where(u => (u.Distance - u.CombatReach - 1 <= range && u.InLineOfSpellSight && u.Combat && u.Attackable && u.IsAlive && u.IsValid && !u.IsPet && (u.IsTargetingMeOrPet || u.IsTargetingMyPartyMember || u.IsTargetingMyRaidMember)) || (!Me.IsInInstance && u.Name.Contains("Dummy"))); }
        // Returns every dotted enemies
        public IEnumerable<WoWUnit> AllEnemyMobsHasMyDOT(string aura) { return AllEnemyMobs.Where(u => GetSpellCooldown(aura).TotalMilliseconds > 0); }
        // Returns every unfriendly unit near current target
        public IEnumerable<WoWUnit> UnfriendlyUnitsNearTarget(float distance)
        {
            var dist = distance * distance;
            var curTarLocation = Me.CurrentTarget.Location;
            return NearbyUnfriendlyUnits.Where(
                        p => p.IsValid && p.Location.DistanceSqr(curTarLocation) <= dist).ToList();
        }

        // Check for the next dottable target to dot
        public WoWUnit NextApplyDOTTarget(string aura, double range, double timeToRefresh)
        {
            WoWUnit target = (from unit in GetEveryDottableTargets(range)
                              //where unit.ThreatInfo.RawPercent < 90 (Wondering if threat is useful XD)
                              where MyLivingBomb_Timeleft(aura, unit) < timeToRefresh
                              select unit).FirstOrDefault();
            return target;
        }

        static double MyLivingBomb_Timeleft(string auraName, WoWUnit u)
        {
            if (u == null || !u.IsValid || !u.IsAlive)
                return 0;

            var aura = u.GetAllAuras().FirstOrDefault(a => a.Name == auraName && a.CreatorGuid == Me.Guid);
            return aura != null ? aura.TimeLeft.TotalMilliseconds : 0;
        }

        #endregion          

        #region Hotkeys

        public static ModifierKeys GetModifierKey(string value)
        {
            switch (value)
            {
                case "Ctrl":
                    return ModifierKeys.Control;
                case "Shift":
                    return ModifierKeys.Shift;
                case "Alt":
                    return ModifierKeys.Alt;
                case "Win":
                    return ModifierKeys.Win;
            }

            return ModifierKeys.NoRepeat;
        }

        public static Keys GetHotkey(string value)
        {
            switch (value)
            {
                case "F1":
                    return Keys.F1;
                case "F2":
                    return Keys.F2;
                case "F3":
                    return Keys.F3;
                case "F4":
                    return Keys.F4;
            }

            return Keys.None;
        }

        public static void Hotkeys_Init()
        {
            if (!FireMageSettings.Instance.EnableHotKeys)
            {
                if (HotkeysManager.Hotkeys.Any())
                {
                    var myHKs = new List<string>();

                    toNyxLog("Removing Hotkeys, please wait...");

                    myHKs.AddRange(HotkeysManager.Hotkeys.Select(hotkey => hotkey.Name));

                    foreach (var myHK in myHKs)
                    {
                        HotkeysManager.Unregister(myHK);
                        toNyxLog(myHK + " Bind now removed/unregistered");
                    }
                }
            }
            else
            {
                // AOE HotKey

                if (FireMageSettings.Instance.AoEHotKey != "None" && HotkeysManager.Hotkeys.All(hk => hk.Name != "AOE"))
                {
                    HotkeysManager.Register("AOE", GetHotkey(FireMageSettings.Instance.AoEHotKey), GetModifierKey(FireMageSettings.Instance.HotKeyModifier), hk => AOE_Toggle());
                    if (FireMageSettings.Instance.HotKeyModifier != "None")
                        toNyxLog("AOE Bind now ready, press {0} + {1} to enable/disable AOE spells", FireMageSettings.Instance.HotKeyModifier, FireMageSettings.Instance.AoEHotKey);
                    else
                        toNyxLog("AOE Bind now ready, press {0} to enable/disable AOE spells", FireMageSettings.Instance.AoEHotKey);

                }
            }
        }

        private static void AOE_Toggle()
        {
            FireMageSettings.Instance.EnableAOE = !FireMageSettings.Instance.EnableAOE;
            toNyxLog("AoE Rotation Enabled : " + FireMageSettings.Instance.EnableAOE);
            FireMageSettings.Instance.Save();
        }

        #endregion

    }
}
